module CodeRust where

import AbsRust
import qualified Data.Map as Map
import Data.Char
import Data.List
import PrintRust
import EnvRust

initCode :: Code
initCode = Map.empty
   
initPC :: PC
initPC = 0

initLabel :: Int
initLabel = 0

initTemp :: Int
initTemp = 0

constAddr :: Const -> Address
constAddr c = Cnst c

varAddr :: Id -> Address
varAddr i = AVar i

tempAddr :: Int -> (Address,Int)
tempAddr i = (Temp i, i+1)

intLabel :: Int -> (Label,Int)
intLabel i = (L i, i+1)

funLabel :: FunIdent -> Maybe Int -> Label
funLabel fi n = F fi n

nullLabel :: Label
nullLabel = N

compItem :: Item -> Item -> Ordering
compItem (IStat _ _ _ ) (IFun _ _ _ _ ) = LT
compItem (IStat _ _ _ ) (IStat _ _ _ ) = EQ
compItem (IFun _ _ _ _ ) (IStat _ _ _ ) = GT
compItem (IFun _ _ _ _ ) (IFun _ _ _ _ ) = EQ

compStmt :: Stmt -> Stmt -> Ordering
compStmt (Let _ _ _ _ ) (SItem _ ) = LT
compStmt (Let _ _ _ _ ) _ = EQ
compStmt (RExprStmt _ ) (SItem _ ) = LT
compStmt (RExprStmt _ ) _ = EQ
compStmt (SItem i1 ) (SItem i2 ) = compItem i1 i2
compStmt (SItem _ ) _ = GT

aErr :: Error -> [Error] -> [Error]
aErr [] xs = xs
aErr x xs = err:xs
   where
      err = "Error: "++x

addError :: Type -> [Error] -> [Error]
addError (TErr s) xs = aErr s xs
addError (Array _ t) xs = addError t xs
addError (Pointer t) xs = addError t xs
addError _ xs = xs

merge = (++)

--sostituisce la label dell'istruzione con la label fornita come 
--secondo argomento
changeLabel :: Instruction -> Label -> Instruction
changeLabel (IfRel r a1 a2 _) lab = (IfRel r a1 a2 lab)
changeLabel (If a1 _) lab = (If a1 lab)
changeLabel (Goto _) lab = (Goto lab)

newLabel :: Int -> Maybe Label -> (Int,Maybe Label)
newLabel lab Nothing = (l,(Just ml))
   where
      (ml,l) = intLabel lab
newLabel l ml = (l,ml)

--esegue il backpatching della lista di istruzioni associate ai PC(program counter),
--utilizzando la label fornita se presente, altrimenti la genera.
--restituisce il Code aggiornato, l'indice per la prossima label e la
--label utilizzata 
backPatch :: [PC] -> Code -> Int -> Maybe Label -> (Code,Int,Maybe Label)
backPatch [] code l ml = (code,l,ml)
backPatch xs code l ml = backP xs code l ml 
backP xs code l Nothing = (c,l',(Just lab))
   where
      (lab,l') = intLabel l
      c = foldr (bp lab) code xs
      bp lb pc cd = c'
         where
            (Just (ml,inst)) = Map.lookup pc cd
            inst' = changeLabel inst lb
            (c',_,_) = insertCode pc (ml,inst') cd

backP xs code l lab@(Just lb) = (c,l,lab)
   where
      c = foldr (bp lb) code xs
      bp lb pc cd = c'
         where
            (Just (ml,inst)) = Map.lookup pc cd
            inst' = changeLabel inst lb
            (c',_,_) = insertCode pc (ml,inst') cd

--inserisce la labeled instruction nel code utilizzando come indice il pc
insertCode :: PC -> LabInst -> Code -> (Code,PC,Maybe Label)
insertCode pc (mlab,inst) code = (c,p,Nothing)
   where
      c = Map.insert pc (mlab,inst) code
      p = pc + 1

--genera il salto alla prima istruzione della funzione main()
genGotoMain :: Code -> PC -> Int -> [PC] -> (Code,PC,Int)
genGotoMain code pc l [] = (c',p',l)
   where
      (c',p',_) = genGotoLabel code pc Nothing (Just fun)
      fun = funLabel (Fun "main" 0) (Just 0)

genGotoMain code pc l xs = (c',pc,l')
   where
      (c',l',_) = backPatch xs code l (Just fun)
      fun = funLabel (Fun "main" 0) (Just 0)

genNoop :: Code -> PC -> Maybe Label -> (Code,PC,Maybe Label)
genNoop code pc mlab = insertCode pc (mlab,noop) code
   where
      noop = Noop

genGotoLabel :: Code -> PC -> Maybe Label -> Maybe Label -> (Code,PC,Maybe Label)
genGotoLabel code pc mlab (Just lab) = (c,p,m)
   where
      goto = Goto lab
      (c,p,m) = insertCode pc (mlab,goto) code

genGotoLabel c p m _ = (c,p,m)

genGotoN :: Code -> PC -> Maybe Label -> [PC] -> (Code,PC,Maybe Label,[PC])
genGotoN code pc mlab backList = (c,p,m,bl)
   where
      goto = Goto nullLabel
      (c,p,m) = insertCode pc (mlab,goto) code
      bl = pc : backList

genIfRel :: Code -> PC -> Int -> Maybe Label -> [PC] -> [PC] -> RelOp -> Maybe Address -> Maybe Address -> (Code,PC,Int,Maybe Label,[PC],[PC])
genIfRel code pc l mlab truelist falselist rOp (Just adr1) (Just adr2) = (c',p',l,m',tl,fl)
   where
      (c,p,m) = insertCode pc (mlab,inst) code
      inst = IfRel rOp adr1 adr2 nullLabel
      (c',p',m',fl) = genGotoN c p m falselist
      tl = pc : truelist
      
genIfRel code pc l mlab truelist falselist _ _ _ = (code,pc,l,mlab,truelist,falselist)

genIf :: Code -> PC -> Int -> Maybe Label -> [PC] -> [PC] -> Maybe Address -> (Code,PC,Int,Maybe Label,[PC],[PC])
genIf code pc l mlab truelist falselist (Just adr1) = (c',p',l,m',tl,fl)
   where
      (c,p,m) = insertCode pc (mlab,inst) code
      inst = If adr1 nullLabel
      (c',p',m',fl) = genGotoN c p m falselist
      tl = pc : truelist
      
genIf code pc l mlab truelist falselist _ = (code,pc,l,mlab,truelist,falselist)

genRetAddr :: Code -> PC -> Maybe Label -> Maybe Address -> (Code,PC,Maybe Label)
genRetAddr code pc mlab (Just addr) = (c,p,m)
   where
      (c,p,m) = insertCode pc (mlab,ret) code
      ret = Ret addr

genRetAddr c p m _ = (c,p,m)

genAssBin :: Code -> PC -> Int -> Maybe Label -> InfixOp -> Maybe Address -> Maybe Address -> Maybe Address -> (Code,PC,Int,Maybe Label,Maybe Address)
genAssBin c p t m op adr1 adr2 Nothing = genAssBin c p t' m op adr1 adr2 (Just temp)
   where
      (temp, t') = tempAddr t

genAssBin c p t m op (Just adr1) (Just adr2) (Just adr) = (c',p',t,m',(Just adr))
   where
      (c',p',m') = insertCode p (m,inst) c
      inst = AssBin op adr1 adr2 adr

genAssUn :: Code -> PC -> Int -> Maybe Label -> UnaryOp -> Maybe Address -> Maybe Address -> (Code,PC,Int,Maybe Label,Maybe Address)
genAssUn c p t m op adr1 Nothing = genAssUn c p t' m op adr1 (Just temp)
   where
      (temp,t') = tempAddr t

genAssUn c p t m op (Just adr1) (Just adr) = (c',p',t,m',(Just adr))
   where
      (c',p',m') = insertCode p (m,inst) c
      inst = AssUn op adr1 adr

genCopy :: Code -> PC -> Int -> Maybe Label -> Maybe Address -> Maybe Address -> (Code,PC,Int,Maybe Label,Maybe Address)
genCopy c p t m adr1 Nothing = genCopy c p t' m adr1 (Just temp)
   where
      (temp,t') = tempAddr t

genCopy c p t m (Just adr1) a@(Just adr) = (c',p',t,m',a)
   where
      (c',p',m') = insertCode p (m,inst) c
      inst = Copy adr1 adr

genCastOp :: Code -> PC -> Int -> Maybe Label -> Type -> Maybe Address -> Maybe Address -> (Code,PC,Int,Maybe Label,Maybe Address)
genCastOp c p t m typ adr1 Nothing = genCastOp c p t' m typ adr1 (Just temp)
   where
      (temp,t') = tempAddr t

genCastOp c p t m typ (Just adr1) (Just adr) = (c',p',t,m',(Just adr))
   where
      (c',p',m') = insertCode p (m,inst adr) c
      inst ad = CastOp typ adr1 ad

genPar :: Code -> PC -> Int -> Int -> Maybe Label -> Maybe Address -> (Code,PC,Int,Int,Maybe Label)
genPar c p l t m (Just adr) = (c',p',l,t,m')
   where
      (c',p',m') = insertCode p (m,inst) c
      inst = Par adr

genCall :: Code -> PC -> Int -> Int -> Maybe Label -> Label -> Maybe Address -> (Code,PC,Int,Int,Maybe Label,Maybe Address)
genCall c p l t m fi Nothing = genCall c p l t' m fi (Just temp)
   where
      (temp,t') = tempAddr t

genCall c p l t m fi (Just adr) = (c',p',l,t,m',(Just adr))
   where
      (c',p',m') = insertCode p (m,inst adr) c
      inst ad = Call ad fi

genAssDeref :: Code -> PC -> Int -> Int -> Maybe Label -> Maybe Address -> Maybe Address -> (Code,PC,Int,Int,Maybe Label,Maybe Address)
genAssDeref c p l t m adr1 Nothing = genAssDeref c p l t' m adr1 (Just temp)
   where
      (temp,t') = tempAddr t

genAssDeref c p l t m (Just adr1) (Just adr) = (c',p',l,t,m',(Just adr))
   where
      (c',p',m') = insertCode p (m,inst) c
      inst = AssDeref adr1 adr

genAEl :: Code -> PC -> Int -> Int -> Maybe Label -> Maybe Address -> Maybe Address -> Maybe Address -> (Code,PC,Int,Int,Maybe Label,Maybe Address)
genAEl c p l t m lv rv Nothing = genAEl c p l t' m lv rv (Just temp)
   where
      (temp,t') = tempAddr t
   
genAEl c p l t m (Just lv) (Just rv) a@(Just adr) = (c',p',l,t,m',a)
   where
      (c',p',m') = insertCode p (m,inst) c
      inst = AEl lv rv adr

genAssAEl :: Code -> PC -> Int -> Maybe Label -> Maybe Address -> Maybe Address -> Maybe Address -> (Code,PC,Int,Maybe Label)    
genAssAEl c p t m (Just addr) (Just adr) (Just caddr) = (c',p',t,m')
   where
      (c',p',m') = insertCode p (m,inst) c
      inst = AssAEl addr adr caddr
      
genAssAEl c p t m Nothing adr caddr = genAssAEl c p t' m (Just temp) adr caddr
   where
      (temp,t') = tempAddr t

genAssRef :: Code -> PC -> Int -> Maybe Label -> Maybe Address -> Maybe Address -> (Code,PC,Int,Maybe Label,Maybe Address)
genAssRef c p t m (Just adr) a@(Just ad) = (c',p',t,m',a)
   where
      (c',p',m') = insertCode p (m,inst) c
      inst = AssRef adr ad

genAssRef c p t m adr Nothing = genAssRef c p t' m adr (Just temp)
   where
      (temp,t') = tempAddr t
      
genAssVtoP :: Code -> PC -> Int -> Maybe Label -> Maybe Address -> Maybe Address -> (Code,PC,Int,Maybe Label,Maybe Address)
genAssVtoP c p t m adr Nothing = genAssVtoP c p t' m adr (Just temp)
   where
      (temp,t') = tempAddr t

genAssVtoP c p t m (Just adr) a@(Just ad) = (c',p',t,m',a)
   where
      (c',p',m') = insertCode p (m,inst) c
      inst = AssVtoP adr ad

genArrTupRExpr :: (Code,PC,Int,Int,Maybe Label,[PC],Maybe Address) -> [Maybe Address] -> (Code,PC,Int,Int,Maybe Label,[PC],Maybe Address)
genArrTupRExpr (c1,pc1,l1,t1,ml1,nl1,Nothing) = genArrTuple (c1,pc1,l1,tt,ml1,nl1,jtemp)
   where
      (temp,tt) = tempAddr t1
      jtemp = Just temp

genArrTuple (c1,pc1,l1,t1,ml1,nl1,ad) ads = (cf,pcf,lf,tf,mlf,nlf,ad)
   where
      (cf,pcf,lf,tf,mlf,nlf,_) = foldr f (c1,pc1,l1,t1,ml1,nl1,0) ads
      f adr (c,pc,l,t,ml,nl,idx) = (c2,pc2,lb,t2,ml2,[],idx+1)
         where
            (cb,lb,mlb) = backPatch nl c l ml
            (c2,pc2,t2,ml2) = genAssAEl cb pc t mlb adr ad (Just cadr)
            cadr = constAddr (Int idx)

genParS :: (Code,PC,Int,Int,Maybe Label,[PC]) -> [Maybe Address] -> (Code,PC,Int,Int,Maybe Label,[PC])
genParS = foldr f
   where
      f adr (c,pc,l,t,ml,nl) = (c1,pc1,l1,t1,ml1,[])
         where
            (cb,lb,mlb) = backPatch nl c l ml
            (c1,pc1,l1,t1,ml1) = genPar cb pc lb t mlb adr

genAssgn :: Code -> PC -> Int -> Maybe Label -> LExpr -> Maybe Address -> Maybe Address -> (Code,PC,Int,Maybe Label,Maybe Address)
genAssgn c1 pc1 t1 ml1 (SId _ _) rval lval = genCopy c1 pc1 t1 ml1 rval lval
genAssgn c1 pc1 t1 ml1 _ rval lval = genAssVtoP c1 pc1 t1 ml1 rval lval

genAssignOp :: Code -> PC -> Int -> Maybe Label -> InfixOp -> LExpr -> Maybe Address -> Maybe Address -> Maybe Address -> (Code,PC,Int,Maybe Label,Maybe Address)
genAssignOp c1 pc1 t1 ml1 op (SId _ _) rval rval1 lval = genAssBin c1 pc1 t1 ml1 op rval rval1 lval
genAssignOp c1 pc1 t1 ml1 op _ rval rval1 lval = (c3,pc3,t3,ml3,lv2)
   where
      (c2,pc2,t2,ml2,lv2) = genAssBin c1 pc1 t1 ml1 op rval rval1 Nothing
      (c3,pc3,t3,ml3,lv3) = genAssVtoP c2 pc2 t2 ml2 lv2 lval
      
--restituisce il codice generato o gli errori se presenti
genCode :: Env -> Program -> String
genCode env = genProgCode env ([],initCode,initPC,initLabel,initTemp)

--genera il codice corrispondente agli item dichiarati ed i relativi errori
-- nel caso in cui nn ci siano errori, restituisce il codice generato, altrimenti gli errori stessi
genProgCode :: Env -> ([Error],Code,PC,Int,Int) -> Program -> String
genProgCode env (err,code,pc,lab,temp) (Prog is perr)
   |null concatErr = printCode $ Map.elems c2
   |otherwise = concatErr
   where
         (c,p,ml,initList) = genGotoN code pc Nothing []
         e = aErr perr err
         (_,_,e1,c1,p1,l1,t1,_,il1) = genItemSCode env (initPath,initBlockTemp,e,c,p,lab,temp,ml,initList) is1
         is1 = sortBy compItem (reverse is)
         (c2,p2,l2) = genGotoMain c1 p1 l1 il1
         concatErr = concat (reverse e1)

genItemSCode :: Env -> (Path,Int,[Error],Code,PC,Int,Int,Maybe Label,[PC]) -> [Item] -> (Path,Int,[Error],Code,PC,Int,Int,Maybe Label,[PC])
genItemSCode env = foldr (flip (genItemCode env))

--aggiorna la tupla in input con il codice generato e gli errori trovati relativi all'item esplorato
genItemCode :: Env -> (Path,Int,[Error],Code,PC,Int,Int,Maybe Label,[PC]) -> Item -> (Path,Int,[Error],Code,PC,Int,Int,Maybe Label,[PC])
genItemCode env (pat,bkt,err,code,pc,lab,temp,mlab,initlist) (IFun i ps typ (bk,bktyp)) = (pat,b1,e4,c2,pc2,lb,t1,mlab,initlist)
      where
         (p1,b1,e1,c1,pc1,l1,t1,ml1,nl1,_,_,adr1) = genBlockCode env (fpat,bkt,err,code,pc,lab,temp,flab,[],[],[],Nothing) bk
         (cb,lb,mlb) = backPatch nl1 c1 l1 ml1
         (c2,pc2,ml2) = genRetAddr cb pc1 mlb adr1
         flab = Just $ funLabel fi mnum
         fpat = updatePath i pat
         fi = funIdent i ps
         mnum = fMaybeNum fs
         fs = lookupFun env fi pat
         e2 = genParErr e1 ps
         e3 = addError bktyp e2
         e4 = addError typ e3
         genParErr = foldr f
            where
               f p err = addError (ptype p) err 

genItemCode env (pat,bkt,err,code,pc,lab,temp,mlab,initlist) (IStat i typ (re,te)) = (pat,bkt1,e,c2,pc2,lb,t2,ml2,[])
   where
      (_,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,adr1) = genRExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,initlist,[],[],Nothing) re
      (cb,lb,mlb) = backPatch nl1 c1 l1 ml1
      (c2,pc2,t2,ml2,_) = genCopy cb pc1 t1 mlb adr1 vadr
      vadr = Just $ varAddr i
      e2 = addError te e1
      e = addError typ e2

genStmtSCode :: Env -> (Path,Int,[Error],Code,PC,Int,Int,Maybe Label,[PC],[PC],[PC]) -> [Stmt] -> (Path,Int,[Error],Code,PC,Int,Int,Maybe Label,[PC],[PC],[PC])
genStmtSCode env = foldr (flip (genStmtCode env))

--aggiorna la tupla in input con il codice generato e gli errori trovati relativi allo statement esplorato
genStmtCode :: Env -> (Path,Int,[Error],Code,PC,Int,Int,Maybe Label,[PC],[PC],[PC]) -> Stmt -> (Path,Int,[Error],Code,PC,Int,Int,Maybe Label,[PC],[PC],[PC])
genStmtCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue) (Let _ v typ Nothing) = (pat,bkt,e,code,pc,lab,temp,mlab,nextlist,break,continue)
   where
      (tadr,tt) = tempAddr temp
      (e1,_,_,_,_,_,_,_) = genVarCode (err,code,pc,lab,tt,mlab,nextlist,Just tadr) v
      e = addError typ e1

genStmtCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue) (Let _ v typ (Just (re,te))) = (pat,bkt1,e,c2,pc2,l2,t2,ml2,nl2,break1,cont1)
   where
      (_,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,adr1) = genRExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,Nothing) re
      (e2,c2,pc2,l2,t2,ml2,nl2,_) = genVarCode (e1,c1,pc1,l1,t1,ml1,nl1,adr1) v
      e3 = addError te e2
      e = addError typ e3

genStmtCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue) (RExprStmt (re,te)) = (pat,bkt1,e,c1,pc1,l1,t1,ml1,nl1,break1,cont1)
   where
      (_,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,_) = genRExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,Nothing) re
      e = addError te e1

genStmtCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue) (SItem item) = (pat,bkt1,e1,c1,pc1,l1,t1,ml1,nextlist,break,continue)
   where
      (_,bkt1,e1,c1,pc1,l1,t1,ml1,_) = genItemCode env (pat,bkt,err,code,pc,lab,temp,mlab,[]) item

--esplora la variabile per aggiornare la lista di errori, il codice e gli altri attributi della tupla in input
genVarCode :: ([Error],Code,PC,Int,Int,Maybe Label,[PC],Maybe Address) -> Var -> ([Error],Code,PC,Int,Int,Maybe Label,[PC],Maybe Address)
genVarCode (e1,c1,pc1,l1,t1,ml1,nl1,taddr) (Var i er) = (e2,c2,pc2,l,t2,ml2,[],vadr)
   where
      (c,l,ml) = backPatch nl1 c1 l1 ml1
      (c2,pc2,t2,ml2,_) = genCopy c pc1 t1 ml taddr vadr
      vadr = Just $ varAddr i
      e2 = aErr er e1

genVarCode (e1,c1,pc1,l1,t1,ml1,nl1,taddr) (VTup vs) = (e2,c2,pc2,l2,t2,ml2,nl2,tad)
   where
      (e2,c2,pc2,l2,t2,ml2,nl2,tad,_) = foldr f (e1,c1,pc1,l1,t1,ml1,nl1,taddr,0) (reverse vs)
      f (Var i err) (e,c,pc,l,t,ml,nl,tdr,idx) = (e2,c2,pc2,l2,t2,ml2,[],tdr,idx+1)
         where
            (cc,ll,mll) = backPatch nl c l ml
            (c2,pc2,l2,t2,ml2,_) = genAEl cc pc ll t mll tdr jidx vadr 
            vadr = Just $ varAddr i
            jidx = Just $ constAddr cidx
            cidx = Int idx
            e2 = aErr err e
      f v@(VTup _) (e,c,pc,l,t,ml,nl,tdr,idx) = (e3,c3,pc3,l3,t3,ml3,nl3,tdr,idx+1)
         where
            (cc,ll,mll) = backPatch nl c l ml
            (c2,pc2,l2,t2,ml2,tddr) = genAEl cc pc ll t mll tdr jidx Nothing
            (e3,c3,pc3,l3,t3,ml3,nl3,_) = genVarCode (e,c2,pc2,l2,t2,ml2,[],tddr) v
            jidx = Just $ constAddr cidx
            cidx = Int idx

genRExprSCode :: Env -> (Path,Int,[Error],Code,PC,Int,Int,Maybe Label,[PC],[PC],[PC],[Maybe Address]) -> [(RExpr,Type)] -> (Path,Int,[Error],Code,PC,Int,Int,Maybe Label,[PC],[PC],[PC],[Maybe Address])
genRExprSCode env = foldr f
   where
      f (re,typ) (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,ads) = (pat,bkt1,e,c1,pc1,l1,t1,ml1,nl1,break1,cont1,ads')
         where
            (_,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,adr1) = genRExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,Nothing) re
            e = addError typ e1
            ads' = adr1 : ads

--aggiorna la tupla in input con errori e codice relativo all'assegnamento tra lexpr e rexpr,
-- valutando prima la lexpr, poi la rexpr, infine eseguendo l'assegnamento tra gli indirizzi ottenuti
genRExprAssignOpCode :: Env -> (Path,Int,[Error],Code,PC,Int,Int,Maybe Label,[PC],[PC],[PC],Maybe Address) -> InfixOp -> (LExpr,Type) -> (RExpr,Type) -> (Path,Int,[Error],Code,PC,Int,Int,Maybe Label,[PC],[PC],[PC],Maybe Address)
genRExprAssignOpCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,adr) aOp (le,typ1) (re,typ2) = (pat,bkt2,e,c3,pc3,lb,t3,ml3,[],break2,cont2,cadr)
   where
      (lrval,t) = tempAddr temp
      (_,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,(lv1,rv1)) = genLExprCode env (pat,bkt,err,code,pc,lab,t,mlab,nextlist,break,continue,(Nothing,Just lrval)) le
      (_,bkt2,e2,c2,pc2,l2,t2,ml2,nl2,break2,cont2,rv2) = genRExprCode env (pat,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,Nothing) re
      (cb,lb,mlb) = backPatch nl2 c2 l2 ml2
      (c3,pc3,t3,ml3,_) = genAssignOp cb pc2 t2 mlb aOp le rv1 rv2 lv1
      cadr = Just $ constAddr Unit
      e3 = addError typ2 e2
      e = addError typ1 e3

genRExprCode :: Env -> (Path,Int,[Error],Code,PC,Int,Int,Maybe Label,[PC],[PC],[PC],Maybe Address) -> RExpr -> (Path,Int,[Error],Code,PC,Int,Int,Maybe Label,[PC],[PC],[PC],Maybe Address)
genRExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,adr) (Assgn Assign (LExpr (le,typ3),typ1) (re,typ2)) = (pat,bkt2,e,c3,pc3,lb,t3,ml3,[],break2,cont2,cadr)
   where
      (_,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,(lv1,_)) = genLExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,(Nothing,Nothing)) le
      (_,bkt2,e2,c2,pc2,l2,t2,ml2,nl2,break2,cont2,rv2) = genRExprCode env (pat,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,Nothing) re
      (cb,lb,mlb) = backPatch nl2 c2 l2 ml2
      (c3,pc3,t3,ml3,_) = genAssgn cb pc2 t2 mlb le rv2 lv1
      cadr = Just $ constAddr Unit
      e3 = addError typ2 e2
      e4 = addError typ3 e3
      e = addError typ1 e4

genRExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,adr) (Assgn (AssgnArith aOp) (LExpr le,typ1) re) = (pat,bkt1,e,c1,pc1,l1,t1,ml1,nl1,break1,cont1,lv1)
   where
      (_,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,lv1) = genRExprAssignOpCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,adr) (ArithOp aOp) le re
      e = addError typ1 e1

genRExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,adr) (Assgn (AssgnBool bOp) (LExpr le,typ1) re) = (pat,bkt1,e,c1,pc1,l1,t1,ml1,nl1,break1,cont1,lv1)
   where
      (_,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,lv1) = genRExprAssignOpCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,adr) (BoolOp bOp) le re
      e = addError typ1 e1

genRExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,adr) (Assgn op (r1,typ1) (r2,typ2)) = (pat,bkt2,e,c2,pc2,l2,t2,ml2,nl2,break2,cont2,cadr)
   where
      (_,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,adr1) = genRExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,Nothing) r1
      (_,bkt2,e2,c2,pc2,l2,t2,ml2,nl2,break2,cont2,adr2) = genRExprCode env (pat,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,Nothing) r2
      cadr = Just $ constAddr Unit
      e3 = addError typ2 e2
      e = addError typ1 e3

--aggiorna la tupla in input con errori e codice relativo alla rexpr,
-- valutando prima la rexpr alla sinistra dell'operatore infisso, poi quella alla destra, infine eseguendo l'assegnamento tra gli indirizzi ottenuti
genRExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,adr) (InfixOp op (r1,typ1) (r2,typ2)) = (pat,bkt2,e,c,p,lb,t,ml,[],break2,cont2,ad)
   where
      (_,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,adr1) = genRExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,Nothing) r1
      (_,bkt2,e2,c2,pc2,l2,t2,ml2,nl2,break2,cont2,adr2) = genRExprCode env (pat,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,Nothing) r2
      (cb,lb,mlb) = backPatch nl2 c2 l2 ml2
      (c,p,t,ml,ad) = genAssBin cb pc2 t2 mlb op adr1 adr2 adr
      e3 = addError typ2 e2
      e = addError typ1 e3

genRExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,adr) (UnaryOp op (r1,typ1)) = (pat,bkt1,e,c,p,lb,t,ml,[],break1,cont1,ad)
   where
      (_,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,adr1) = genRExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,Nothing) r1
      (cb,lb,mlb) = backPatch nl1 c1 l1 ml1
      (c,p,t,ml,ad) = genAssUn cb pc1 t1 mlb op adr1 adr
      e = addError typ1 e1

genRExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,adr) (FCall i rs) = (pat,bkt1,e1,c3,pc3,l3,t3,ml3,[],break1,cont1,adr3)
   where
      (_,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,ads) = genRExprSCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,[]) (reverse rs)
      (c2,pc2,l2,t2,ml2,nl2) = genParS (c1,pc1,l1,t1,ml1,nl1) ads
      (cb,lb,mlb) = backPatch nl2 c2 l2 ml2
      (c3,pc3,l3,t3,ml3,adr3) = genCall cb pc2 lb t2 mlb flab adr
      flab = funLabel fi mnum
      fi = funIdent i rs
      fs = lookupFun env fi pat      
      mnum = fMaybeNum fs

genRExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,Nothing) (Const c) = (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,ad)
   where
      ad = Just $ constAddr c
      
genRExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,addr) (Const c) = (pat,bkt,err,c2,pc2,l1,t2,ml2,[],break,continue,adr)
   where
      (c1,l1,ml1) = backPatch nextlist code lab mlab
      (c2,pc2,t2,ml2,adr) = genCopy c1 pc temp ml1 ad addr
      ad = Just $ constAddr c

genRExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,addr) (LExpr (le,typ)) = (pat,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,rv1)
   where
      (_,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,(_,rv1)) = genLExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,(Nothing,addr)) le
      e = addError typ e1

genRExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,addr) (Ref (le,typ)) = (pat,bkt1,e,c2,pc2,l2,t2,ml2,nl2,break1,cont1,rv2)
   where
      (_,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,(lv1,_)) = genLExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,(Nothing,Nothing)) le
      (c2,pc2,l2,t2,ml2,nl2,rv2) = genRefCode (c1,pc1,l1,t1,ml1,nl1,addr) lv1
      e = addError typ e1

genRExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,adr) (Cast typ (r1,typ1)) = (pat,bkt1,e,c,p,lb,t,ml,[],break1,cont1,ad)
   where
      (_,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,adr1) = genRExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,Nothing) r1
      (cb,lb,mlb) = backPatch nl1 c1 l1 ml1
      (c,p,t,ml,ad) = genCastOp cb pc1 t1 mlb typ adr1 adr
      e = addError typ1 e1

genRExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,adr) (Coertion _ typ (r1,typ1)) = (pat,bkt1,e,c,p,lb,t,ml,[],break1,cont1,ad)
   where
      (_,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,adr1) = genRExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,Nothing) r1
      (cb,lb,mlb) = backPatch nl1 c1 l1 ml1
      (c,p,t,ml,ad) = genCastOp cb pc1 t1 mlb typ adr1 adr
      e = addError typ1 e1

genRExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,adr) (TRExpr rs) = (pat,bkt1,e1,c2,pc2,l2,t2,ml2,nl2,break1,cont1,adr2)
   where
      (_,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,ads) = genRExprSCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,[]) (reverse rs)
      (c2,pc2,l2,t2,ml2,nl2,adr2) = genArrTupRExpr (c1,pc1,l1,t1,ml1,nl1,Nothing) ads

genRExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,adr) (ArrRExpr rs) = (pat,bkt1,e1,c2,pc2,l2,t2,ml2,nl2,break1,cont1,adr2)
   where
      (_,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,ads) = genRExprSCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,[]) (reverse rs)
      (c2,pc2,l2,t2,ml2,nl2,adr2) = genArrTupRExpr (c1,pc1,l1,t1,ml1,nl1,Nothing) ads

genRExprCode env a (Jmp j) = genJmpCode env a j
genRExprCode env a (Iter i) = genIterCode env a i
genRExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,adr) (Sel (iff,typ)) = (pat,b1,e2,c1,pc1,l1,t1,m1,nl1,br1,cont1,ad)
   where
      (p1,b1,e1,c1,pc1,l1,t1,m1,nl1,br1,cont1,ad) = genIfRExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,adr) iff
      e2 = addError typ e1

genRExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,adr) (REBlk (b,typ)) = (pat,b1,e2,c1,pc1,l1,t1,m1,nl1,br1,cont1,ad)
   where
      (p1,b1,e1,c1,pc1,l1,t1,m1,nl1,br1,cont1,ad) = genBlockCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,adr) b
      e2 = addError typ e1

genRefCode :: (Code,PC,Int,Int,Maybe Label,[PC],Maybe Address) -> Maybe Address -> (Code,PC,Int,Int,Maybe Label,[PC],Maybe Address)
genRefCode (c1,pc1,l1,t1,ml1,nl1,adr1) Nothing = (c1,pc1,l1,t1,ml1,nl1,adr1)
genRefCode (c1,pc1,l1,t1,ml1,nl1,adr1) lv1 = (c3,pc3,l2,t3,ml3,[],adr3)
   where
      (c2,l2,ml2) = backPatch nl1 c1 l1 ml1
      (c3,pc3,t3,ml3,adr3) = genAssRef c2 pc1 t1 ml2 lv1 adr1

-- esplorando la rexpr operando del deref, viene aggiornata la tupla e si ottiene l'indirizzo cui fare il dereferencing,
--viene aggiunta l'istruzione relativa al dereferencing, avendo prima effettuato il backpatching della nextlist della rexpr
genLExprCode :: Env -> (Path,Int,[Error],Code,PC,Int,Int,Maybe Label,[PC],[PC],[PC],(Maybe Address,Maybe Address)) -> LExpr -> (Path,Int,[Error],Code,PC,Int,Int,Maybe Label,[PC],[PC],[PC],(Maybe Address,Maybe Address))
genLExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,(lval,rval)) (Deref (re,typ)) = (pat,bkt1,e,c2,pc2,l2,t2,ml2,[],break1,cont1,(adr1,rv2))
   where
      (_,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,adr1) = genRExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,Nothing) re
      (cb,lb,mlb) = backPatch nl1 c1 l1 ml1
      (c2,pc2,l2,t2,ml2,rv2) = genAssDeref cb pc1 lb t1 mlb adr1 rval
      e = addError typ e1

--viene valutato prima la lexpr, poi la rexpr; ottenuti gli indirizzi, si provvede a generare le relative istruzioni per restituire la coppia 
--(lvalue,rvalue) relative all array element.
genLExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,(lval,rval)) (ArrayEl (le,typ1) (re,typ2)) = (pat,bkt2,e,c4,pc4,l4,t4,ml4,[],break2,cont2,(lv3,rv4))
   where
      (_,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,(_,lv1)) = genLExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,(Nothing,Nothing)) le
      (_,bkt2,e2,c2,pc2,l2,t2,ml2,nl2,break2,cont2,rv2) = genRExprCode env (pat,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,Nothing) re
      (cb,lb,mlb) = backPatch nl2 c2 l2 ml2
      (c3,pc3,t3,ml3,lv3) = genAssBin cb pc2 t2 mlb (ArithOp Add) lv1 rv2 lval
      (c4,pc4,l4,t4,ml4,rv4) = genAEl c3 pc3 lb t3 ml3 lv1 rv2 rval
      e3 = addError typ2 e2
      e = addError typ1 e3

genLExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,(lval,Nothing)) (SId i er) = (pat,bkt,e,code,pc,lab,temp,mlab,nextlist,break,continue,(jvar,jvar))
   where
      e = aErr er err
      jvar = Just $ varAddr i

genLExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,(lval,rval)) le@(SId _ _) = (pat,bkt1,e1,c2,pc2,lb,t2,ml2,[],break1,cont1,(lv1,rv2))
   where
      (_,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,(lv1,rv1)) = genLExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,(Nothing,Nothing)) le
      (cb,lb,mlb) = backPatch nl1 c1 l1 ml1
      (c2,pc2,t2,ml2,rv2) = genCopy cb pc temp mlb rv1 rval

--viene aggiunta alla lista contenente gli indirizzi delle istruzioni associate al break, l'indirizzo dell'istruzione genereta,
-- in modo tale che in seguito possa essere fatto il backpatching 
genJmpCode :: Env -> (Path,Int,[Error],Code,PC,Int,Int,Maybe Label,[PC],[PC],[PC],Maybe Address) -> JumpRExpr -> (Path,Int,[Error],Code,PC,Int,Int,Maybe Label,[PC],[PC],[PC],Maybe Address)
genJmpCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,adr) (Break) = (pat,bkt,err,c1,pc1,l,temp,ml1,[],break1,continue,cadr)
      where
         (c,l,ml) = backPatch nextlist code lab mlab
         (c1,pc1,ml1,break1) = genGotoN c pc ml break
         cadr = Just $ constAddr Unit

--viene aggiunta alla lista contenente gli indirizzi delle istruzioni associate al continue, l'indirizzo dell'istruzione genereta,
-- in modo tale che in seguito possa essere fatto il backpatching 
genJmpCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,adr) (Continue) = (pat,bkt,err,c1,pc1,l,temp,ml1,[],break,cont1,cadr)
      where
         (c,l,ml) = backPatch nextlist code lab mlab
         (c1,pc1,ml1,cont1) = genGotoN c pc ml continue
         cadr = Just $ constAddr Unit

genJmpCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,adr) (RetExp (re,te)) = (pat,bkt1,e2,c2,pc2,lb,t1,ml2,[],break1,cont1,addr)
      where
         (_,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,addr) = genRExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,adr) re
         (cb,lb,mlb) = backPatch nl1 c1 l1 ml1
         (c2,pc2,ml2) = genRetAddr cb pc1 mlb addr
         e2 = addError te e1

genBlockCode :: Env -> (Path,Int,[Error],Code,PC,Int,Int,Maybe Label,[PC],[PC],[PC],Maybe Address) -> Block -> (Path,Int,[Error],Code,PC,Int,Int,Maybe Label,[PC],[PC],[PC],Maybe Address)
genBlockCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,adr) (Block ss (re,typ)) = (pat,bkt2,e,c2,pc2,l2,t2,ml2,nl2,break2,cont2,adr2)
      where
         (_,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1) = genStmtSCode env (pat1,bktt,err,code,pc,lab,temp,mlab,nextlist,break,continue) ss1
         ss1 = sortBy compStmt (reverse ss)
         (_,bkt2,e2,c2,pc2,l2,t2,ml2,nl2,break2,cont2,adr2) = genRExprCode env (pat1,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,Nothing) re
         e = addError typ e2
         pat1 = updatePath (show bkt) pat
         bktt = updateBkt bkt

-- per prima cosa viene valutata la guardia, poi viene fatto il backpatch della truelist con la label che sarà associata al blocco del then,
-- infine si fa il merging della falselist e della nextlist del blocco e si restituisce la tupla aggiornata
genIfRExprCode :: Env -> (Path,Int,[Error],Code,PC,Int,Int,Maybe Label,[PC],[PC],[PC],Maybe Address) -> IfRExpr -> (Path,Int,[Error],Code,PC,Int,Int,Maybe Label,[PC],[PC],[PC],Maybe Address)
genIfRExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,adr) (IfNoElse (re,typ) (bk,bktyp)) = (pat,bkt3,e,c3,pc3,l3,t3,ml3,nlist,break3,cont3,cadr)
   where
      (_,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,truelist,falselist) = genGuardCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,[],[]) re
      (c2,l2,ml2) = backPatch truelist c1 l1 Nothing
      (_,bkt3,e3,c3,pc3,l3,t3,ml3,nl3,break3,cont3,adr3) = genBlockCode env (pat,bkt1,e1,c2,pc1,l2,t1,ml2,nl1,break1,cont1,Nothing) bk
      nlist = merge falselist nl3
      e4 = addError typ e3
      e = addError bktyp e4
      cadr = Just $ constAddr Unit

-- per prima cosa viene valutata la guardia, poi viene fatto il backpatch della truelist con la label che sarà associata al blocco del then,
-- viene generata un istruzione per copiare il valore del blocco nell'indirizzo associato alla if expression,
-- viene valutato l'elseblock, generata la relativa istruzione di copia nell'indirizzo dell'if,
-- infine si aggiornano gli errori trovati e si restituisce la tupla
genIfRExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,adr) (IfElse (re,typ) (bk,bktyp) (ebk,ebktyp)) = (pat,bkt6,e,c7,pc7,lb1,t7,ml7,nl5,break6,cont6,tempif)
   where
      (_,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,truelist,falselist) = genGuardCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,[],[]) re
      tl1 = merge nl1 truelist
      (_,bkt3,e3,c3,pc3,l3,t3,ml3,nl3,break3,cont3,adr3) = genBlockCode env (pat,bkt1,e1,c1,pc1,l1,t1,ml1,tl1,break1,cont1,Nothing) bk
      (cb,lb,mlb) = backPatch nl3 c3 l3 Nothing
      (c4,pc4,t4,ml4,tempif) = genCopy cb pc3 t3 mlb adr3 Nothing
      (c5,pc5,ml5,nl5) = genGotoN c4 pc4 ml4 []
      (_,bkt6,e6,c6,pc6,l6,t6,ml6,nl6,break6,cont6,adr6) = genElseBlockCode env (pat,bkt3,e3,c5,pc5,lb,t4,ml5,falselist,break3,cont3,Nothing) ebk
      (cb1,lb1,mlb1) = backPatch nl6 c6 l6 ml6
      (c7,pc7,t7,ml7,_) = genCopy cb1 pc6 t6 mlb1 adr6 tempif
      e7 = addError typ e6
      e8 = addError bktyp e7
      e = addError ebktyp e8

genElseBlockCode :: Env -> (Path,Int,[Error],Code,PC,Int,Int,Maybe Label,[PC],[PC],[PC],Maybe Address) -> ElseBlock -> (Path,Int,[Error],Code,PC,Int,Int,Maybe Label,[PC],[PC],[PC],Maybe Address)
genElseBlockCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,adr) (EBlk (bk,bktyp)) = (pat,bkt1,e,c1,pc1,l1,t1,ml1,nl1,break1,cont1,adr1)
   where
      (_,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,adr1) =  genBlockCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,adr) bk
      e = addError bktyp e1

genElseBlockCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,adr) (EIf (eif,eiftyp)) = (pat,bkt1,e,c1,pc1,l1,t1,ml1,nl1,break1,cont1,adr1)
   where
      (_,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,adr1) =  genIfRExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,adr) eif
      e = addError eiftyp e1

-- per prima cosa viene valutata la guardia, poi viene fatto il backpatch della truelist con la label che sarà associata al blocco del while,
-- viene fatto il backpatch della continuelist con la label associata all'inizio del while
-- infine si fa il merging della falselist e della breaklist del blocco e si restituisce la tupla aggiornata
genIterCode :: Env -> (Path,Int,[Error],Code,PC,Int,Int,Maybe Label,[PC],[PC],[PC],Maybe Address) -> IterRExpr -> (Path,Int,[Error],Code,PC,Int,Int,Maybe Label,[PC],[PC],[PC],Maybe Address)
genIterCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,adr) (While (re,typ) (bk,bktyp)) = (pat,bkt3,e,c5,pc4,l3,t3,ml4,nlist,break,continue,cadr)
   where
      (c,l,ml) = backPatch nextlist code lab mlab
      (ll,mll) = newLabel l ml
      (_,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,truelist,falselist) = genGuardCode env (pat,bkt,err,c,pc,ll,temp,mll,[],[],[],[],[]) re
      (c2,l2,ml2) = backPatch truelist c1 l1 Nothing
      (_,bkt3,e3,c3,pc3,l3,t3,ml3,nl3,break3,cont3,_) = genBlockCode env (pat,bkt1,e1,c2,pc1,l2,t1,ml2,nl1,break1,cont1,Nothing) bk
      (c4,pc4,ml4,clist) = genGotoN c3 pc3 ml3 nl3
      conlist = merge clist cont3
      (c5,_,_) = backPatch conlist c4 l3 mll
      nlist = merge falselist break3
      e4 = addError typ e3
      e = addError bktyp e4
      cadr = Just $ constAddr Unit

genIterCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,adr) (Loop (bk,bktyp)) = (pat,bkt1,e,c3,pc2,l1,t1,ml2,break1,break,continue,cadr)
   where
      (c,l,ml) = backPatch nextlist code lab mlab
      (ll,mll) = newLabel l ml
      (_,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,_) = genBlockCode env (pat,bkt,err,c,pc,ll,temp,mll,[],[],[],Nothing) bk
      (c2,pc2,ml2,clist) = genGotoN c1 pc1 ml1 nl1
      conlist = merge clist cont1
      (c3,_,_) = backPatch conlist c2 l1 mll
      e = addError bktyp e1
      cadr = Just $ constAddr Unit

--viene generato il codice per valutare la guardia con short-cut e vengono aggiornate in maniera opportuna la truelist e la falselist con gli indirizzi delle istruzione generate  
genGuardCode :: Env -> (Path,Int,[Error],Code,PC,Int,Int,Maybe Label,[PC],[PC],[PC],[PC],[PC]) -> RExpr -> (Path,Int,[Error],Code,PC,Int,Int,Maybe Label,[PC],[PC],[PC],[PC],[PC])
genGuardCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,truelist,falselist) (Const (Bool True)) = (pat,bkt,err,c1,pc1,l,temp,ml1,[],break,continue,tl1,falselist)
   where
      (c,l,ml) = backPatch nextlist code lab mlab
      (c1,pc1,ml1,tl1) = genGotoN c pc ml truelist

genGuardCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,truelist,falselist) (Const (Bool False)) = (pat,bkt,err,c1,pc1,l,temp,ml1,[],break,continue,truelist,fl1)
   where
      (c,l,ml) = backPatch nextlist code lab mlab
      (c1,pc1,ml1,fl1) = genGotoN c pc ml falselist

genGuardCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,truelist,falselist) (UnaryOp Not (re,typ1)) = (pat,bkt1,e,c1,pc1,l1,t1,ml1,nl1,break1,cont1,tlist,flist)
   where
      (_,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,tl,fl) = genGuardCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,[],[]) re
      e = addError typ1 e1
      flist = merge falselist tl
      tlist = merge truelist fl

genGuardCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,truelist,falselist) (InfixOp (RelOp rOp) (r1,typ1) (r2,typ2)) = (pat,bkt2,e,c,p,l,t2,ml,[],break2,cont2,tl,fl)
   where
      (_,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,adr1) = genRExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,Nothing) r1
      (_,bkt2,e2,c2,pc2,l2,t2,ml2,nl2,break2,cont2,adr2) = genRExprCode env (pat,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,Nothing) r2
      e3 = addError typ2 e2
      e = addError typ1 e3
      (cb,lb,mlb) = backPatch nl2 c2 l2 ml2
      (c,p,l,ml,tl,fl) = genIfRel cb pc2 lb mlb truelist falselist rOp adr1 adr2

genGuardCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,truelist,falselist) (InfixOp (BoolOp Or) (r1,typ1) (r2,typ2)) = (pat,bkt2,e,c2,pc2,l2,t2,ml2,nl2,break2,cont2,tl2,fl2)
   where
      (_,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,tl1,fl1) = genGuardCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,truelist,[]) r1
      (cb,lb,mlb) = backPatch fl1 c1 l1 ml1
      (_,bkt2,e2,c2,pc2,l2,t2,ml2,nl2,break2,cont2,tl2,fl2) = genGuardCode env (pat,bkt1,e1,cb,pc1,lb,t1,mlb,nl1,break1,cont1,tl1,falselist) r2
      e3 = addError typ2 e2
      e = addError typ1 e3

genGuardCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,truelist,falselist) (InfixOp (BoolOp And) (r1,typ1) (r2,typ2)) = (pat,bkt2,e,c2,pc2,l2,t2,ml2,nl2,break2,cont2,tl2,fl2)
   where
      (_,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,tl1,fl1) = genGuardCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,[],falselist) r1
      (cb,lb,mlb) = backPatch tl1 c1 l1 ml1
      (_,bkt2,e2,c2,pc2,l2,t2,ml2,nl2,break2,cont2,tl2,fl2) = genGuardCode env (pat,bkt1,e1,cb,pc1,lb,t1,mlb,nl1,break1,cont1,truelist,fl1) r2
      e3 = addError typ2 e2
      e = addError typ1 e3

genGuardCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,truelist,falselist) re = (pat,bkt1,e1,c,p,l,t1,ml,[],break1,cont1,tl,fl)
   where
      (_,bkt1,e1,c1,pc1,l1,t1,ml1,nl1,break1,cont1,adr1) = genRExprCode env (pat,bkt,err,code,pc,lab,temp,mlab,nextlist,break,continue,Nothing) re
      (cb,lb,mlb) = backPatch nl1 c1 l1 ml1
      (c,p,l,ml,tl,fl) = genIf cb pc1 lb mlb truelist falselist adr1

